﻿using System;
using System.Collections.Generic;
using System.Text;
using Vara.Utility;
using System.Data;

namespace Vara.Person
{
    public class PersonController : IPersonActions
    {
        #region IPersonActions Implementations

        private List<IPerson> _people = null;
        public virtual void InsertPerson(IPerson person)
        {
            // if a person is a stranger then insert
            if (!person.IsReadOnly)
            {
                List<ISqlEngineVariable> vars = this.setupPersonInsertUpdateParameters(person);
                using (ISqlEngine Engine = VaraSqlEngineProvider.Get())
                {
                    Engine.ExecuteProcedure("Insert_Person", vars.ToArray());
                }
                this.Refresh_People_List();
            }
        }

        public virtual void UpdatePerson(IPerson person)
        {
            // if person is a stranger then update
            if (!person.IsReadOnly)
            {
                List<ISqlEngineVariable> vars = this.setupPersonInsertUpdateParameters(person);
                using (ISqlEngine Engine = VaraSqlEngineProvider.Get())
                {
                    Engine.ExecuteProcedure("Update_Person", vars.ToArray());
                }
                this.Refresh_People_List();
            }
        }

        public virtual void DeletePerson(IPerson person)
        {
            // if person is a stranger then delete
            if (!person.IsReadOnly)
            {
                using (ISqlEngine Engine = VaraSqlEngineProvider.Get())
                {
                    Engine.ExecuteProcedure("Delete_Person",
                        VaraSqlEngineProvider.GetParam("@id", person.ID.ToString()));
                }

                this.People.Remove(this.ReturnPerson(person.Reference, person.TypeName));
            }
        }

        public virtual IPerson ReturnPerson(string reference, string type)
        {
            type = type.Replace("Stranger", "External");
            // find stranger, staffmember or student.
            return this.People.Find(new Predicate<IPerson>(delegate(IPerson p)
            {
                return p.Reference == reference && p.TypeName == type;
            }));
        }

        public virtual void Refresh_People_List()
        {
            DataTable TableOfPeople = null;
            using (ISqlEngine Engine = VaraSqlEngineProvider.Get())
            {
                TableOfPeople = Engine.ExecuteProcedure("Return_People");
            }

            if (TableOfPeople.Rows.Count > 0)
            {
                _people = new List<IPerson>();
                foreach (DataRow r in TableOfPeople.Rows)
                {
                    IPerson newPerson = this.setupPerson(r);

                    this.People.Add(newPerson);
                }
            }
        }

        public virtual List<IPerson> People
        {
            get
            {
                if (_people == null)
                {
                    _people = new List<IPerson>();
                    this.Refresh_People_List();
                }
                return _people;
            }
        }

        public virtual DataTable Search_People(string Firstname,string Lastname,string Reference, bool IsStaff, bool IsStudent, bool IsStranger)
        {
            List<IPerson> people = this.People;

            if (IsStaff)
            {
                people.RemoveAll(new Predicate<IPerson>(delegate(IPerson p){

                    return (p as StaffMember) == null;
                }));
            }

            if (IsStudent)
            {
                people.RemoveAll(new Predicate<IPerson>(delegate(IPerson p)
                {

                    return (p as Student) == null;
                }));
            }
            
            if (IsStranger)
            {
                people.RemoveAll(new Predicate<IPerson>(delegate(IPerson p)
                {

                    return (p as Stranger) == null;
                }));
            }


            DataView DataViewPeople = new DataView();
            DataViewPeople.Table = List_To_DataTable.ConvertToDataTable(people);

            string peopleQuery = string.Empty;

            peopleQuery = string.IsNullOrEmpty(Firstname) ? string.Empty : "Firstname LIKE '%"+Firstname+"%'";

            peopleQuery += string.IsNullOrEmpty(Lastname) ? string.Empty : string.IsNullOrEmpty(peopleQuery) ? "Lastname LIKE '%"+Lastname+"%'" : " AND Lastname LIKE '%"+Lastname+"%'";

            peopleQuery += string.IsNullOrEmpty(Reference) ? string.Empty : string.IsNullOrEmpty(peopleQuery) ? "Reference LIKE '%"+Reference+"%'" : " AND Reference LIKE '%"+Reference+"%'";

            DataViewPeople.RowFilter = peopleQuery;
            return DataViewPeople.ToTable();
        }

        #endregion

        /// <summary>
        /// sets up an Iperson instance from a datarow 
        /// </summary>
        /// <param name="r"></param>
        /// <returns></returns>
        private IPerson setupPerson(DataRow r)
        {
            //instantiate the correct type
            IPerson newPerson = null;
            if (r["Type"].ToString() == "Stranger")
            {
                newPerson = new Stranger((int)r["ID"]);
            }
            else if (r["Type"].ToString() == "Staff")
            {
                newPerson = new StaffMember((int)r["ID"]);
                
            }
            else if (r["Type"].ToString() == "Student")
            {
                newPerson = new Student((int)r["ID"]);
            }

            // setup common data
            newPerson.Firstname = r["Firstname"].ToString();
            newPerson.Lastname = r["Lastname"].ToString();
            newPerson.Address1 = r["Address1"].ToString();
            newPerson.Address2 = r["Address2"].ToString();
            newPerson.Address3 = r["Address3"].ToString();
            newPerson.Postcode = r["Postcode"].ToString();
            newPerson.TelephoneNumber = r["TelephoneNumber"].ToString();
            newPerson.EmailAddress = r["EmailAddress"].ToString();
            newPerson.Reference = r["Reference"].ToString();
            return newPerson;
        }

        /// <summary>
        /// sets up sql parameters from an Iperson instance for the insert or update procedure
        /// </summary>
        /// <param name="person"></param>
        /// <returns></returns>
        private List<ISqlEngineVariable> setupPersonInsertUpdateParameters(IPerson person)
        {
            List<ISqlEngineVariable> vars = new List<ISqlEngineVariable>();

            // add id if there is one
            if (person.ID > 0)
            {
                vars.Add(VaraSqlEngineProvider.GetParam("@id", person.ID.ToString()));
            }

            // create main varaibles range
            vars.AddRange(new ISqlEngineVariable[]{
                
                    VaraSqlEngineProvider.GetParam("@FirstName",person.Firstname),
                    VaraSqlEngineProvider.GetParam("@Lastname",person.Lastname),
                    VaraSqlEngineProvider.GetParam("@address1",person.Address1),
                    VaraSqlEngineProvider.GetParam("@address2",person.Address2),
                    VaraSqlEngineProvider.GetParam("@address3",person.Address3),
                    VaraSqlEngineProvider.GetParam("@postcode",person.Postcode),
                    VaraSqlEngineProvider.GetParam("@telephoneNumber",person.TelephoneNumber),
                    VaraSqlEngineProvider.GetParam("@emailAddress",person.EmailAddress)

            });

            return vars;
        }
    }
}
